#pragma once

#define _USE_MATH_DEFINES
#include<math.h>

class Location
{
public:
	Location()
		:X(0.0),
		Y(0.0)
	{
	}
	Location(float x , float y)
		:X(x),
		Y(y)
	{
	}
	Location(const Location& anotherLocation)
		:X(anotherLocation.X),
		Y(anotherLocation.Y)
	{
	}
	Location(const Location& original , float directionX , float directionY , float distance)
	{
		X = original.X;
		Y = original.Y;
		MoveTowardLocation(Location(X + directionX , Y + directionY) , distance);
	}
	Location(const Position& bwapiPosition)
		:X(bwapiPosition.x()),
		Y(bwapiPosition.y())
	{
	}
	float GetDistance(const Location& anotherLocation) const
	{
		float dx = X - anotherLocation.X;
		float dy = Y - anotherLocation.Y;
		return sqrt(dx * dx + dy * dy);
	}
	void MoveTowardLocation(const Location& targetPosition , float distance)
	{
		float length = GetDistance(targetPosition);
		if(length > 0.0)
		{
			float delta = distance / length;
			X += (targetPosition.X - X) * delta;
			Y += (targetPosition.Y - Y) * delta;
		}
	}
	void MoveTowardDirection(const Location& direction , float distance)
	{
		if(distance > 0.0)
		{
			Location nonConstDirection(direction);
			nonConstDirection.Normalize();
			X += nonConstDirection.X * distance;
			Y += nonConstDirection.Y * distance;
		}
	}
	void Set(const float& x , const float& y)
	{
		X = x;
		Y = y;
	}
	float AngleToTarget(const Location& target)
	{
		float answer = atan2f(Y - target.Y , target.X - X);
		if(answer < 0.0f)
		{
			answer += M_PI * 2.0f;
		}
		return answer;
	}
	Position ToBWAPI_Position() const
	{
		return Position(X , Y);
	}
	void Normalize()
	{
		float length(sqrtf(X * X + Y * Y));
		X /= length;
		Y /= length;

	}
	//--
	float X;
	float Y;
};

bool TurnTowardAngle(float& angleNow , const float& target , const float& offset) //true for arrival
{
	float otherSide = target - M_PI;
	const float M_2PI = M_PI * 2.0f;
	if(otherSide < 0.0f)
	{
		otherSide += M_2PI;
	}

	if(target < M_PI)
	{
		if(angleNow < target || angleNow > otherSide)
		{
			angleNow += offset;
			if(angleNow > M_2PI)
			{
				angleNow -= M_2PI;
			}
			if(angleNow < target || angleNow > otherSide)
			{
				return false;
			}
			else
			{
				angleNow = target;
				return true;
			}
		}
		else
		{
			angleNow -= offset;
			if(angleNow < 0.0f)
			{
				angleNow += M_2PI;
			}
			if(angleNow < target || angleNow > otherSide)
			{
				angleNow = target;
				return true;
			}
			else
			{
				return false;
			}
		}
	}
	else
	{
		if(angleNow < target && angleNow > otherSide)
		{
			angleNow += offset;
			if(angleNow > M_2PI)
			{
				angleNow -= M_2PI;
			}
			if(angleNow < target && angleNow > otherSide)
			{
				return false;
			}
			else
			{
				angleNow = target;
				return true;
			}
		}
		else
		{
			angleNow -= offset;
			if(angleNow < 0.0f)
			{
				angleNow += M_2PI;
			}
			if(angleNow < target && angleNow > otherSide)
			{
				angleNow = target;
				return true;
			}
			else
			{
				return false;
			}
		}
	}
}